using System;
using System.Windows.Forms;
using System.Drawing;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

using AGG;
using AGG.Image;

namespace AGG.UI
{
    /*
    class AggPlatformDXSpecific : Form
    {
        PlatformSupport m_app;
        Device DX_Device;
        public bool m_WindowContentNeedsRedraw;

        public AggPlatformDXSpecific(GuiHalSurfaceMore app)
        {
            m_app = (PlatformSupport)app;

            //this.ClientSize = new Size(256, 256);
            this.Text = "AggPlatformDX";
            m_WindowContentNeedsRedraw = true;
        }

        public bool InitializeDirect3D()
        {
            try
            {
                PresentParameters pps = new PresentParameters();
                pps.Windowed = true;
                pps.SwapEffect = SwapEffect.Discard;
                pps.EnableAutoDepthStencil = false;
                pps.PresentFlag |= PresentFlag.LockableBackBuffer;
                pps.MultiSample = MultiSampleType.None;
                DX_Device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, pps);
                return true;
            }
            catch (DirectXException e)
            {
                MessageBox.Show(e.ToString(), "Error");
                return false;
            }
        }

        internal void Render()
        {
            if (DX_Device == null)
            {
                return;
            }

            DX_Device.Clear(ClearFlags.Target, Color.White, 1.0f, 0);
            DX_Device.BeginScene();

            if (this.ClientRectangle.Width != m_app.backBuffer.Width()
                || this.ClientRectangle.Height != m_app.backBuffer.Height())
            {
                throw new InvalidDataException("the back buffer must be the same size as the client area");
            }

            using (Surface s = DX_Device.GetBackBuffer(0, 0, BackBufferType.Mono))
            {
                int pitch;
                using (GraphicsStream graphicsStream = s.LockRectangle(this.ClientRectangle, LockFlags.None, out pitch))
                {
                    unsafe
                    {
                        int sourceOffset;
                        Byte[] sourceBuffer = m_app.backBuffer.GetBuffer(out sourceOffset);
                        
                        byte* pDestBuffer = (byte*)graphicsStream.InternalDataPointer;
                        int* pDestBufferInt = (int*)pDestBuffer;

                        int height = m_app.backBuffer.Height();
                        int scanWidth = m_app.backBuffer.Width() * 4;
                        int numLongs = scanWidth / 4;
                        fixed (byte* pSourceBuffer = &sourceBuffer[sourceOffset])
                        {
                            int* pSourceBufferInt = (int*)pSourceBuffer;
                            for (int y = 0; y < height; y++)
                            {
                                int destOffsetInt = y * pitch / 4;
                                int sourceOffsetInt = m_app.backBuffer.GetBufferOffsetXY(0, height-y-1) / 4;
                                for (int x = 0; x < numLongs; x++)
                                {
                                    pDestBufferInt[destOffsetInt++] = pSourceBufferInt[sourceOffsetInt++];
                                }
                            }
                        }
                    }
                }
                s.UnlockRectangle();
            }


            // Rendering is done here
            DX_Device.EndScene();
            DX_Device.Present();
        }

        protected override void OnKeyUp(System.Windows.Forms.KeyEventArgs windowsKeyEvent)
        {
            AGG.UI.KeyEventArgs aggKeyEvent = new AGG.UI.KeyEventArgs((AGG.UI.Keys)windowsKeyEvent.KeyData);
            m_app.OnKeyUp(aggKeyEvent);

            windowsKeyEvent.Handled = aggKeyEvent.Handled;
            windowsKeyEvent.SuppressKeyPress = aggKeyEvent.SuppressKeyPress;

            base.OnKeyUp(windowsKeyEvent);
        }

        protected override void OnKeyDown(System.Windows.Forms.KeyEventArgs windowsKeyEvent)
        {
            AGG.UI.KeyEventArgs aggKeyEvent = new AGG.UI.KeyEventArgs((AGG.UI.Keys)windowsKeyEvent.KeyData);
            m_app.OnKeyDown(aggKeyEvent);

            windowsKeyEvent.Handled = aggKeyEvent.Handled;
            windowsKeyEvent.SuppressKeyPress = aggKeyEvent.SuppressKeyPress;

            base.OnKeyDown(windowsKeyEvent);
        }

        protected override void OnKeyPress(System.Windows.Forms.KeyPressEventArgs windowsKeyPressEvent)
        {
            AGG.UI.KeyPressEventArgs aggKeyPressEvent = new AGG.UI.KeyPressEventArgs(windowsKeyPressEvent.KeyChar);
            m_app.OnKeyPress(aggKeyPressEvent);
            windowsKeyPressEvent.Handled = aggKeyPressEvent.Handled;

            base.OnKeyPress(windowsKeyPressEvent);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if (m_WindowContentNeedsRedraw)
            {
                m_app.OnDraw(m_app.NewGraphics2D());
                m_WindowContentNeedsRedraw = false;
            }

            Render();
        }

        protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs mouseEvent)
        {
            base.OnMouseDown(mouseEvent);

            int Y = mouseEvent.Y;
            Y = (int)m_app.height() - Y;

            AGG.UI.MouseEventArgs aggMouseEvent = new AGG.UI.MouseEventArgs((AGG.UI.MouseButtons)mouseEvent.Button, mouseEvent.Clicks, mouseEvent.X, Y, mouseEvent.Delta);

            m_app.SetChildCurrent(aggMouseEvent.X, aggMouseEvent.Y);
            m_app.OnMouseDown(aggMouseEvent);
        }

        protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs mouseEvent)
        {
            base.OnMouseMove(mouseEvent);

            int Y = mouseEvent.Y;
            Y = (int)m_app.height() - Y;

            AGG.UI.MouseEventArgs aggMouseEvent = new AGG.UI.MouseEventArgs((AGG.UI.MouseButtons)mouseEvent.Button, mouseEvent.Clicks, mouseEvent.X, Y, mouseEvent.Delta);

            m_app.OnMouseMove(aggMouseEvent);
        }

        protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs mouseEvent)
        {
            base.OnMouseUp(mouseEvent);

            int Y = mouseEvent.Y;
            Y = (int)m_app.height() - Y;

            AGG.UI.MouseEventArgs aggMouseEvent = new AGG.UI.MouseEventArgs((AGG.UI.MouseButtons)mouseEvent.Button, mouseEvent.Clicks, mouseEvent.X, Y, mouseEvent.Delta);

            m_app.OnMouseUp(aggMouseEvent);
        }

        protected override void OnMouseWheel(System.Windows.Forms.MouseEventArgs mouseEvent)
        {
            base.OnMouseWheel(mouseEvent);

            int Y = mouseEvent.Y;
            Y = (int)m_app.height() - Y;

            AGG.UI.MouseEventArgs aggMouseEvent = new AGG.UI.MouseEventArgs((AGG.UI.MouseButtons)mouseEvent.Button, mouseEvent.Clicks, mouseEvent.X, Y, mouseEvent.Delta);

            m_app.OnMouseWheel(aggMouseEvent);
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);

            m_app.OnResize(ClientSize.Width, ClientSize.Height);
            m_app.Invalidate();

            m_app.OnResize(e);
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            //base.OnPaintBackground(e);
        }
    }

    public class PlatformSupport : GuiHalSurfaceMore
    {
        private AggPlatformDXSpecific windowsWindowWithDX;
        internal ImageBuffer backBuffer;

        //------------------------------------------------------------------------
        public PlatformSupport(ImageFormats format)
            : base(format)
        {
            windowsWindowWithDX = new AggPlatformDXSpecific(this);//, format);
            if (windowsWindowWithDX.InitializeDirect3D() == false) // Check if D3D could be initialized
            {
                MessageBox.Show("Could not initialize Direct3D.", "Error");
                return;
            }


            m_format = format;
            //m_bpp(windowsWindowWithDX->m_bpp),
            //m_window_flags(0),
            m_wait_mode = true;
            initialWidth = 10;
            initialHeight = 10;

            Caption = "Anti-Grain Geometry Application";

            //Focus();
        }

        public override System.IO.Stream OpenFileDialog(GuiHalSurfaceMore.OpenFileDialogParams openParams)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        //------------------------------------------------------------------------
        public override string Caption
        {
            get
            {
                return windowsWindowWithDX.Text;
            }
            set
            {
                windowsWindowWithDX.Text = value;
            }
        }

        public override void OnIdle() { }
        public override void OnResize(int sx, int sy)
        {
            Bounds = new rect_d(0, 0, sx, sy); ;
#if USE_OPENGL
            if ((m_window_flags & WindowFlags.UseOpenGL) != 0)
            {
                Gl.glViewport(0, 0, (int)Width, (int)Height);					// Reset The Current Viewport


                // The following lines set the screen up for a perspective view. Meaning things in the distance get smaller. 
                // This creates a realistic looking scene. 
                // The perspective is calculated with a 45 degree viewing angle based on the windows width and height. 
                // The 0.1f, 100.0f is the starting point and ending point for how deep we can draw into the screen.

                Gl.glMatrixMode(Gl.GL_PROJECTION);						// Select The Projection Matrix
                Gl.glLoadIdentity();							// Reset The Projection Matrix-

                Gl.glMatrixMode(Gl.GL_MODELVIEW);						// Select The Modelview Matrix
                Gl.glLoadIdentity();
                Gl.glScissor(0, 0, (int)Width, (int)Height);
            }
            else
#endif
            {
                int bitDepth = GuiHalSurfaceMore.GetBitDepthForPixelFormat(m_format);

                backBuffer.Allocate((int)Width, (int)Height, (int)Width * bitDepth / 8, bitDepth);
            }
            NewGraphics2D().Clear(new RGBA_Doubles(1, 1, 1, 1));
        }

        public override Graphics2D NewGraphics2D()
        {
            Graphics2D graphics2D = null;
            if ((m_window_flags & WindowFlags.UseOpenGL) != 0)
            {
                throw new NotSupportedException("DX cannot have an OpenGL surface"); // with a bunch of (fun:) work this could be written, LBB.
                //graphics2D = new RendererOpenGL_DX();
            }
            else
            {
                if (backBuffer != null)
                {
                    graphics2D = backBuffer.NewGraphics2D();
                }
                else
                {
                    throw new NotImplementedException("We don't support float in DX yet.");
                    //graphics2D = m_BackBufferFloat.NewGraphics2D();
                }
            }
            graphics2D.PushTransform();
            return graphics2D;
        }

        public override void OnControlChanged() { }

        public override void Invalidate()
        {
            windowsWindowWithDX.Invalidate();
            windowsWindowWithDX.m_WindowContentNeedsRedraw = true;
        }

        public override void Invalidate(rect_d rectToInvalidate)
        {
            windowsWindowWithDX.Invalidate(new Rectangle(
                (int)System.Math.Floor(rectToInvalidate.Left),
                (int)System.Math.Floor(Height - rectToInvalidate.Top),
                (int)System.Math.Ceiling(rectToInvalidate.Width),
                (int)System.Math.Ceiling(rectToInvalidate.Height)));
            windowsWindowWithDX.m_WindowContentNeedsRedraw = true;
        }

        public override void OnClosing(out bool CancelClose)
        {
            CancelClose = false;
            // your app can implement this is you want to be able to override the close.
        }

        public override void Close()
        {
            windowsWindowWithDX.Close();
        }

        public void update_window()
        {
            if (!windowsWindowWithDX.IsDisposed)
            {
                //Graphics displayGraphics = windowsWindowWithDX.CreateGraphics();
                windowsWindowWithDX.Render();
                //windowsWindowWithDX.display_pmap(displayGraphics);
            }
        }

        public override bool init(int width, int height, WindowFlags flags)
        {
            //if (windowsWindowWithDX.m_sys_format == PlatformSupportAbstract.ImageFormats.pix_format_undefined)
            {
              //  return false;
            }

            m_window_flags = flags;

            initialWidth = width;
            initialHeight = height;

            int bitDepth = GuiHalSurfaceMore.GetBitDepthForPixelFormat(m_format);
            switch (bitDepth)
            {
                case 24:
                    backBuffer = new ImageBuffer(initialWidth, initialHeight, 24, new BlenderBGR());
                    break;

                case 32:
                    backBuffer = new ImageBuffer(initialWidth, initialHeight, 32, new BlenderBGRA());
                    break;

                case 128:
                    throw new NotImplementedException();
                    backBuffer = null;
                    //m_BackBufferFloat = new ImageBufferFloat(initialWidth, initialHeight, 128, new BlenderBGRAFloat());
                    break;

                default:
                    throw new NotImplementedException("Don't support this bit depth yet.");
            }

            System.Drawing.Size clientSize = new System.Drawing.Size();
            clientSize.Width = (int)width;
            clientSize.Height = (int)height;
            windowsWindowWithDX.ClientSize = clientSize;

            if ((m_window_flags & WindowFlags.Resizable) == 0)
            {
                windowsWindowWithDX.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
                windowsWindowWithDX.MaximizeBox = false;
            }

            clientSize.Width = width;
            clientSize.Height = height;
            windowsWindowWithDX.ClientSize = clientSize;

            Bounds = new rect_d(0, 0, width, height);

            OnInitialize();
            windowsWindowWithDX.m_WindowContentNeedsRedraw = true;

            return true;
        }

        public override void OnInitialize()
        {
            NewGraphics2D().Clear(new RGBA_Doubles(1, 1, 1, 1));
            windowsWindowWithDX.Show();

            base.OnInitialize();
        }

        //------------------------------------------------------------------------
        public override void run()
        {
            while (windowsWindowWithDX.Created)
            {
                Application.DoEvents();
                if (m_wait_mode)
                {
                    System.Threading.Thread.Sleep(1);
                }
                else
                {
                    OnIdle();
                }
            }

#if USE_OPENGL
            if ((m_window_flags & WindowFlags.UseOpenGL) != 0)
            {
                windowsWindowWithDX.KillGLWindow();
            }
#endif
        }

        //------------------------------------------------------------------------
        public void start_timer()
        {
            //windowsWindowWithDX.m_StopWatch.Reset();
            //windowsWindowWithDX.m_StopWatch.Start();
        }

        //------------------------------------------------------------------------
        public double elapsed_time()
        {
            //windowsWindowWithDX.m_StopWatch.Stop();
            //return windowsWindowWithDX.m_StopWatch.Elapsed.TotalMilliseconds;
            throw new NotImplementedException();
        }

        public override void message(String msg)
        {
            System.Windows.Forms.MessageBox.Show(msg, "AggSharp message");
        }
    }
*/
}
